package datacache

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/astaxie/beego/logs"

	"gitee.com/haodreams/golib/thread"
)

type Cache struct {
	path    string
	lock    *sync.RWMutex
	mapItem map[int32]*Item
	thread.Thread
	saveFile   *os.File
	createTIme int64
	saveDays   int
}

//Setup 初始化设置
func (me *Cache) Setup() (err error) {
	me.lock = new(sync.RWMutex)
	me.mapItem = map[int32]*Item{}
	me.saveDays = 10
	me.SetSavePath("cache")
	me.BeforStart = me.beforeStart
	me.BeforStop = me.beforeStop
	go me.autoDeleteTimeoutFile()
	return
}

//beforeStart 启动前执行的操作
func (me *Cache) beforeStart() (err error) {
	go me.autoFlush()
	return
}

//beforeStop 停止前执行的操作
func (me *Cache) beforeStop() (err error) {
	return
}

func (me *Cache) GetSavePath() string {
	return me.path
}

func (me *Cache) SetSavePath(path string) (err error) {
	path = strings.Replace(path, "\\", "/", -1)
	if !strings.HasSuffix(path, "/") {
		path += "/"
	}
	me.path = path
	return os.MkdirAll(me.path, 0775)
}

//SetSaveDays 设置保存的天数
func (me *Cache) SetSaveDays(days int) {
	if days < 1 {
		days = 1
	}
	me.saveDays = days
}

//Update 更新内存数据
func (me *Cache) Update(id int32, value float64, status byte, time int64) {
	me.lock.RLock()
	item, ok := me.mapItem[id]
	me.lock.RUnlock()
	if !ok {
		item = new(Item)
		item.ID = id
		item.Status = 0xff
		me.lock.Lock()
		me.mapItem[id] = item
		me.lock.Unlock()
	}
	item.Value = value
	item.Status = status
	item.Time = int32(time)
}

func (me *Cache) save(t int64, all bool) (err error) {
	if me.saveFile != nil {
		t -= t % 600
		me.lock.RLock()
		defer me.lock.RUnlock()
		ok := false
		if all {
			for _, item := range me.mapItem {
				if item != nil {
					if item.Time < int32(t) {
						continue
					}
					ok = true
					_, err = me.saveFile.Write(item.Encode())
					if err != nil {
						logs.Error(err.Error())
						me.saveFile.Close()
						me.saveFile = nil
						return
					}
				}
			}
		} else {
			for _, item := range me.mapItem {
				if item != nil {
					if item.Time < int32(t) {
						continue
					}
					if !FloatEqual(item.LastValue, item.Value) || item.LastStatus != item.Status {
						item.LastValue = item.Value
						item.LastStatus = item.Status
						_, err = me.saveFile.Write(item.Encode())
						if err != nil {
							logs.Error(err.Error())
							me.saveFile.Close()
							me.saveFile = nil
							return
						}
						ok = true
					}
				}
			}
		}
		if ok {
			me.saveFile.Sync()
		}
	}
	return
}

//flush 保存内存中的数据到文件
func (me *Cache) flush() (err error) {
	t := time.Now()
	if (t.Unix()-600) >= me.createTIme || (me.createTIme > t.Unix()) {
		if me.saveFile != nil {
			//保存一次全部数据
			me.save(t.Unix(), true)
			me.saveFile.Close()
		}
		t = time.Unix(t.Unix()-t.Unix()%600, 0)
		path := fmt.Sprintf("%s%s/", me.path, t.Format("20060102"))
		os.Mkdir(path, 0775)
		path += t.Format("1504.dat")
		me.saveFile, err = os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0666)
		//logs.Info(t.Unix(), path, me.path)
		if err != nil {
			logs.Error(err.Error())
			me.saveFile = nil
			return
		} else {
			//保存一次全部数据
			me.save(t.Unix(), true)
		}
		me.createTIme = t.Unix()
	} else {
		me.save(t.Unix(), false)
	}

	return
}

//autoFlush 保存内存中的数据到文件
func (me *Cache) autoFlush() {
	for me.IsRunning() {
		me.flush()
		time.Sleep(time.Second)
	}
}

func (me *Cache) autoDeleteTimeoutFile() {
	t := time.NewTicker(time.Second * 7200)
	for range t.C {
		st := time.Now().Unix() - int64(time.Second*86400*time.Duration(me.saveDays))
		timeout := time.Unix(st, 0).Format("20060102")
		fs, err := ioutil.ReadDir(me.path)
		if err != nil {
			continue
		}
		for _, f := range fs {
			if f.IsDir() {
				if f.Name() < timeout {
					err = os.RemoveAll(me.path + f.Name())
					if err != nil {
						logs.Error(err.Error())
					}
				}
			}
		}
	}
}
